#include <iostream>
#include <string>
#include <cstdio>
#include <cassert>

static int hex_to_i(char ch) {
    if (ch >= '0' && ch <= '9') {
        return (ch - '0');
    }else if (ch >= 'a' && ch <= 'z') {
        return (ch - 'a' + 10);
    }else if (ch >= 'A' && ch <= 'Z') {
        return (ch - 'A' + 10);
    }
    return -1;
}
#define HEX(c) (((c) & 0x0F) > 9 ? (((c) & 0x0F) - 10 + 'a') : (((c) & 0x0F) + '0'))

static std::string urldecode(const std::string &url, bool convert_plus_to_space){
    std::string res;
    for (int i = 0; i < url.size(); i++) {
        /*%0b  有平台万一整成 %b， 那就只整前边的一个字符就行*/
        if (url[i] == '%' && (i+1) < url.size()) {
            int v1 = hex_to_i(url[i+1]);
            int v2 = hex_to_i(url[i+2]);
            if (v1 >= 0 && v2 >= 0) {
                res += v1 * 16 + v2;
                i += 2;
            }else {
                res += v1*16;
                i+=1;
            }
        }else if (convert_plus_to_space && url[i] == '+') {
            res += ' ';
        }else {
            res += url[i];
        }
    }
    return res;
}
/*在RFC3986文档中规定的URL绝对不编码字符： . - _ ~ 以及字母和数字*/
/*还有一个就是在不同的一些标准中的特殊处理：W3C标准规定中规定param中的空格必须被编码为+；  RFC 2396中规定URI中的保留字符需要转换为%HH格式*/
static std::string urlencode(const std::string &url, bool convert_space_to_plus){
    std::string res;
    for (int i = 0; i < url.size(); i++){
        if (isalnum(url[i]) || url[i] == '-' || url[i] == '.' || url[i] == '_' || url[i] == '~') {
            res += url[i];
        }else if (url[i] == ' ' && convert_space_to_plus) {
            res += '+';
        }else if (url[i] == ' ' && !convert_space_to_plus) {
            res += ' ';
        }else {
            char tmp[4];
            snprintf(tmp, 3, "%02X", url[i]);
            res += '%';
            res += HEX(url[i] >> 4);
            res += HEX(url[i]);
        }
    }
    return res;
}

int main()
{
    std::string str = "张文超nihao今年要888-----";
    std::string en = urlencode(str, false);
    std::string de = urldecode(en,false);
    std::cout << en << std::endl;
    std::cout << de << std::endl;
    return 0;
}
